﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using HalconDotNet;

namespace Kimd.Vision
{
	[Serializable]
	public class SectorNB : ShapeNB
	{
		private HTuple _rows;
		private HTuple _cols;
		public PointF Center;
		public float Radius;
		public float Width;
		public float StartAngle;
		public float EndAngle;
		//public bool IsFitCircleMode = false;
		//public int SearchRectCount = 20;
		//public int SearchRectWidth = 20;
		//public bool ReverseAngle = false;
		//public List<Rectangle2NB> SearchRects;

		public SectorNB():
			base()
        {
            TypeName = ShapeType.Sector;
            StartAngle = 0.5233f;
			EndAngle = 4.71f;
			Width = 100;
		}

		private void updateHandlePos()
		{
			_rows = new HTuple();
			_cols = new HTuple();
			_rows = _rows.TupleConcat(new HTuple(Center.Y));
			_cols = _cols.TupleConcat(new HTuple(Center.X));

			float len = Radius;
			float len1 = Radius + Width / 2;
			float len2 = Radius - Width / 2;
			float len3 = (Radius + Width / 2 + 50) / 2;
			_rows = _rows.TupleConcat(new HTuple(Center.Y - len * Math.Sin(StartAngle)));
			_cols = _cols.TupleConcat(new HTuple(Center.X + len * Math.Cos(StartAngle)));
			_rows = _rows.TupleConcat(new HTuple(Center.Y - len * Math.Sin(EndAngle)));
			_cols = _cols.TupleConcat(new HTuple(Center.X + len * Math.Cos(EndAngle)));

			if (StartAngle > EndAngle)
			{
				_rows = _rows.TupleConcat(new HTuple(Center.Y + len1 * Math.Sin((StartAngle + EndAngle) / 2)));
				_cols = _cols.TupleConcat(new HTuple(Center.X - len1 * Math.Cos((StartAngle + EndAngle) / 2)));
				_rows = _rows.TupleConcat(new HTuple(Center.Y + len2 * Math.Sin((StartAngle + EndAngle) / 2)));
				_cols = _cols.TupleConcat(new HTuple(Center.X - len2 * Math.Cos((StartAngle + EndAngle) / 2)));
			}
			else
			{
				_rows = _rows.TupleConcat(new HTuple(Center.Y - len1 * Math.Sin((StartAngle + EndAngle) / 2)));
				_cols = _cols.TupleConcat(new HTuple(Center.X + len1 * Math.Cos((StartAngle + EndAngle) / 2)));
				_rows = _rows.TupleConcat(new HTuple(Center.Y - len2 * Math.Sin((StartAngle + EndAngle) / 2)));
				_cols = _cols.TupleConcat(new HTuple(Center.X + len2 * Math.Cos((StartAngle + EndAngle) / 2)));
			}
		}

		public override void Draw(HWindow window, Graphics g, Func<PointF, PointF> pixel2Window, Func<float, float> lenConvert, bool disableEdit)
		{
			if (disableEdit || IsShowOnly)
			{
				window.SetColor(PaintColor);
				window.SetLineWidth(LineWidth);
				window.SetDraw("margin");
				HObject innerSector = null;
				HObject outerSector = null;
				if (Radius - Width / 2 > 3)
					HOperatorSet.GenCircleSector(out innerSector, new HTuple(Center.Y), new HTuple(Center.X), new HTuple(Radius - Width / 2), new HTuple(StartAngle), new HTuple(EndAngle));
				HOperatorSet.GenCircleSector(out outerSector, new HTuple(Center.Y), new HTuple(Center.X), new HTuple(Radius + Width / 2), new HTuple(StartAngle), new HTuple(EndAngle));
				HObject sector = null;
				if (Radius - Width / 2 > 3)
					HOperatorSet.Difference(outerSector, innerSector, out sector);
				else
					sector = outerSector;
				window.DispObj(sector);
			}
			else
			{
				if (!IsSelected)
				{
					window.SetColor(PaintColor);
					window.SetLineWidth(LineWidth);
					window.SetDraw("margin");
					HObject innerSector = null;
					HObject outerSector = null;
					if(Radius - Width / 2 > 3)
						HOperatorSet.GenCircleSector(out innerSector, new HTuple(Center.Y), new HTuple(Center.X), new HTuple(Radius - Width / 2), new HTuple(StartAngle), new HTuple(EndAngle));
					HOperatorSet.GenCircleSector(out outerSector, new HTuple(Center.Y), new HTuple(Center.X), new HTuple(Radius + Width / 2), new HTuple(StartAngle), new HTuple(EndAngle));
					HObject sector = null;
					if (Radius - Width / 2 > 3)
						HOperatorSet.Difference(outerSector, innerSector, out sector);
					else
						sector = outerSector;
					window.DispObj(sector);
					window.SetColor("yellow");
					updateHandlePos();
                    float size = lenConvert(5);
                    for (int i = 0; i < _rows.Length; i++)
					{
						HTuple angle = new HTuple();
						if (i == 0)
							angle = 0;
						else if (i == 1)
							angle = StartAngle;
						else if (i == 2)
							angle = EndAngle;
						else if (i == 3 || i == 4)
							angle = (StartAngle + EndAngle) / 2;
						window.DispRectangle2(_rows[i].D, _cols[i].D, angle.D, size, size);
					}
				}
				else
				{
					window.SetColor("orange");
					window.SetLineWidth(1);
					window.SetDraw("margin");
					HObject innerSector = null;
					HObject outerSector = null;
					if (Radius - Width / 2 > 3)
						HOperatorSet.GenCircleSector(out innerSector, new HTuple(Center.Y), new HTuple(Center.X), new HTuple(Radius - Width / 2), new HTuple(StartAngle), new HTuple(EndAngle));
					HOperatorSet.GenCircleSector(out outerSector, new HTuple(Center.Y), new HTuple(Center.X), new HTuple(Radius + Width / 2), new HTuple(StartAngle), new HTuple(EndAngle));
					HObject sector = null;
					if (Radius - Width / 2 > 3)
						HOperatorSet.Difference(outerSector, innerSector, out sector);
					else
						sector = outerSector;
					window.DispObj(sector);
					window.SetColor("red");
					updateHandlePos();
                    float size = lenConvert(5);
                    for (int i = 0; i < _rows.Length; i++)
					{
						HTuple angle = new HTuple();
						if (i == 0)
							angle = 0;
						else if (i == 1)
							angle = StartAngle;
						else if (i == 2)
							angle = EndAngle;
						else if (i == 3 || i == 4)
							angle = (StartAngle + EndAngle) / 2;
						window.DispRectangle2(_rows[i].D, _cols[i].D, angle.D, size, size);
					}
				}
                //if (IsFitCircleMode)
                //{
                //	SearchRects = new List<Rectangle2NB>();
                //	window.SetColor("blue");
                //	float anglestep = (EndAngle - StartAngle) / SearchRectCount;
                //	for (int i = 0; i < SearchRectCount; i++)
                //	{
                //		HTuple anglerect = new HTuple();
                //		anglerect = StartAngle + i * anglestep;
                //		HTuple rectcenterrow = new HTuple(Center.Y - Radius * Math.Sin(anglerect));
                //		HTuple rectcentercol = new HTuple(Center.X + Radius * Math.Cos(anglerect));
                //		SearchRects.Add(new Rectangle2NB()
                //		{
                //			Center = new PointF((float)rectcentercol.D, (float)rectcenterrow.D),
                //			Angle = ReverseAngle ? (float)(Math.PI - anglerect.D) : (float)anglerect.D,
                //			Length1 = Width / 2,
                //			Length2 = SearchRectWidth,
                //		});
                //		HOperatorSet.DispRectangle2(window, rectcenterrow, rectcentercol, anglerect, Width / 2, SearchRectWidth);
                //	}
                //	window.SetColor("green");
                //HTuple arrowrow = new HTuple(Center.Y - (Radius + Width / 2 + 50) * Math.Sin((StartAngle + EndAngle) / 2));
                //HTuple arrowcol = new HTuple(Center.X + (Radius + Width / 2 + 50) * Math.Cos((StartAngle + EndAngle) / 2));
                //if (ReverseAngle)
                //    window.DispArrow(arrowrow, arrowcol, new HTuple(Center.Y), new HTuple(Center.X), 20);
                //else
                    //window.DispArrow(new HTuple(Center.Y), new HTuple(Center.X), arrowrow, arrowcol, 20);
                //}
            }
		}

		public override void Change(PointF point)
		{
			switch (ChangeModel)
			{
				case PositionNB.In:
					float dx = point.X - Center.X;
					float dy = point.Y - Center.Y;
					this.Center = new PointF(Center.X + dx, Center.Y + dy);
					break;
				case PositionNB.Create:
					this.Radius = (float)Math.Sqrt(Math.Pow(point.X - Center.X, 2) + Math.Pow(point.Y - Center.Y, 2));
					break;
				case PositionNB.StartAngle:
					HTuple angle = new HTuple();
					HOperatorSet.AngleLx(point.Y, point.X, Center.Y, Center.X, out angle);
					StartAngle = (float)(angle.D + Math.PI);
					break;
				case PositionNB.EndAngle:
					HTuple angle2 = new HTuple();
					HOperatorSet.AngleLx(point.Y, point.X, Center.Y, Center.X, out angle2);
					EndAngle = (float)(angle2.D + Math.PI);
					break;
				case PositionNB.InnerArc:
					HTuple outerradius = new HTuple();
					HOperatorSet.DistancePp(_rows[3], _cols[3], Center.Y, Center.X, out outerradius);
					HTuple innerradius = new HTuple();
					HOperatorSet.DistancePp(point.Y, point.X, Center.Y, Center.X, out innerradius);
					Width = (float)(outerradius.D - innerradius.D);
					Radius = (float)((outerradius.D + innerradius.D) / 2);
					break;
				case PositionNB.OuterArc:
					HTuple innerradius2 = new HTuple();
					HOperatorSet.DistancePp(_rows[4], _cols[4], Center.Y, Center.X, out innerradius2);
					HTuple outerradius2 = new HTuple();
					HOperatorSet.DistancePp(point.Y, point.X, Center.Y, Center.X, out outerradius2);
					Width = (float)(outerradius2.D - innerradius2.D);
					Radius = (float)((outerradius2.D + innerradius2.D) / 2);
					break;
			}
		}

		public override PointF GetCenter()
		{
			return this.Center;
		}

		public override HObject ToRegion()
		{
            HObject innerSector = null;
            HObject outerSector = null;
            if (Radius - Width / 2 > 3)
                HOperatorSet.GenCircleSector(out innerSector, new HTuple(Center.Y), new HTuple(Center.X), new HTuple(Radius - Width / 2), new HTuple(StartAngle), new HTuple(EndAngle));
            HOperatorSet.GenCircleSector(out outerSector, new HTuple(Center.Y), new HTuple(Center.X), new HTuple(Radius + Width / 2), new HTuple(StartAngle), new HTuple(EndAngle));
            HObject sector = null;
            if (Radius - Width / 2 > 3)
                HOperatorSet.Difference(outerSector, innerSector, out sector);
            else
                sector = outerSector;
            return sector;
		}

		public override PositionNB PointOnShape(PointF point, Func<float, float> lenConvert)
        {
            distance2Handle = (int)lenConvert(10);

            updateHandlePos();
			double dcenter = HMisc.DistancePp(new HTuple(point.Y), new HTuple(point.X), new HTuple(_rows[0].D), new HTuple(_cols[0].D));
			if (dcenter < distance2Handle)
				return PositionNB.In;
			double dstart = HMisc.DistancePp(new HTuple(point.Y), new HTuple(point.X), new HTuple(_rows[1].D), new HTuple(_cols[1].D));
			if (dstart < distance2Handle)
				return PositionNB.StartAngle;
			double dend = HMisc.DistancePp(new HTuple(point.Y), new HTuple(point.X), new HTuple(_rows[2].D), new HTuple(_cols[2].D));
			if (dend < distance2Handle)
				return PositionNB.EndAngle;
			double douter = HMisc.DistancePp(new HTuple(point.Y), new HTuple(point.X), new HTuple(_rows[3].D), new HTuple(_cols[3].D));
			if (douter < distance2Handle)
				return PositionNB.OuterArc;
			double dinner = HMisc.DistancePp(new HTuple(point.Y), new HTuple(point.X), new HTuple(_rows[4].D), new HTuple(_cols[4].D));
			if (dinner < distance2Handle)
				return PositionNB.InnerArc;
			return PositionNB.Out;
		}

        public override void ToXmlNode(out Dictionary<string, object> attributes, out Dictionary<string, object> nodes)
        {
			attributes = new Dictionary<string, object>();
			attributes.Add("Color", PaintColor);
			attributes.Add("LineWidth", LineWidth);
			attributes.Add("Type", TypeName.ToString());
			attributes.Add("Operator", RegOperator.ToString());
			nodes = new Dictionary<string, object>();
			nodes.Add("Center", Center.X.ToString("0.000") + "," + Center.Y.ToString("0.000"));
			nodes.Add("StartAngle", StartAngle.ToString("0.000"));
			nodes.Add("EndAngle", EndAngle.ToString("0.000"));
			nodes.Add("Radius", Radius.ToString("0.000"));
			nodes.Add("Width", Width.ToString("0.000"));
			//nodes.Add("IsFitCircleMode", IsFitCircleMode.ToString());
			//nodes.Add("SearchRectCount", SearchRectCount.ToString());
			//nodes.Add("SearchRectWidth", SearchRectWidth.ToString());
			//nodes.Add("ReverseAngle", ReverseAngle.ToString());
			nodes.Add("Alias", string.IsNullOrEmpty(Alias) ? "" : Alias);
		}

		public override void FromXmlNode(XmlNode node)
		{
			RegOperator = (ShapeOperator)Enum.Parse(typeof(ShapeOperator), node.Attributes["Operator"].Value);
			PaintColor = node.Attributes["Color"].Value;
			LineWidth = Int32.Parse(node.Attributes["LineWidth"].Value);

			foreach (XmlNode xn in node.ChildNodes)
			{
				if (xn.Name == "Center")
				{
					Center = new PointF(float.Parse(xn.InnerText.Split(',')[0]),
										float.Parse(xn.InnerText.Split(',')[1]));
				}
				else if (xn.Name == "StartAngle")
				{
					StartAngle = float.Parse(xn.InnerText);
				}
				else if (xn.Name == "EndAngle")
				{
					EndAngle = float.Parse(xn.InnerText);
				}
				else if (xn.Name == "Radius")
				{
					Radius = float.Parse(xn.InnerText);
				}
				else if (xn.Name == "Width")
				{
					Width = float.Parse(xn.InnerText);
				}
				//else if (xn.Name == "IsFitCircleMode")
				//{
				//    IsFitCircleMode = Convert.ToBoolean(xn.InnerText);
				//}
				//else if (xn.Name == "ReverseAngle")
				//{
				//    ReverseAngle = Convert.ToBoolean(xn.InnerText);
				//}
				//else if (xn.Name == "SearchRectCount")
				//{
				//    SearchRectCount = Convert.ToInt32(xn.InnerText);
				//}
				//else if (xn.Name == "SearchRectWidth")
				//{
				//    SearchRectWidth = Convert.ToInt32(xn.InnerText);
				//}
				else if (xn.Name == "Alias")
				{
					Alias = xn.InnerText;
				}
			}
		}
    }
}
